/**
 * Copyright (c) 2011 ~ 2013 Deepin, Inc.
 *               2011 ~ 2013 jouyouyun
 *
 * Author:      jouyouyun <jouyouwen717@gmail.com>
 * Maintainer:  jouyouyun <jouyouwen717@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 **/

package main

import (
	"fmt"
	"github.com/BurntSushi/xgb/xproto"
	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/keybind"
	"github.com/BurntSushi/xgbutil/xevent"
	"os/exec"
	"strings"
)

func GetSystemPairs() map[string]string {
	systemPairs := make(map[string]string)
	for i, k := range SystemIdNameMap {
		if IsInvalidConflict(i) {
			continue
		}
		shortcut := GetSystemValue(k, false)
		action := GetSystemValue(k, true)
		systemPairs[shortcut] = action
	}

	return systemPairs
}

func GetCustomPairs() map[string]string {
	customPairs := make(map[string]string)
	customList := GetCustomList()

	for _, i := range customList {
		if IsInvalidConflict(i) {
			continue
		}
		gs := NewGSettingsById(i)
		if gs == nil {
			continue
		}
		shortcut := gs.GetString(_CUSTOM_KEY_SHORTCUT)
		action := gs.GetString(_CUSTOM_KEY_ACTION)
		customPairs[shortcut] = action
	}

	return customPairs
}

func GrabKeyPairs(accelPairs map[string]string, grab bool) {
	for k, v := range accelPairs {
		if k == "Super" {
			if grab {
				GrabXRecordKey("Super_L", v)
				GrabXRecordKey("Super_R", v)
			} else {
				UngrabXRecordKey("Super_L")
				UngrabXRecordKey("Super_R")
			}
			continue
		}

		shortcut := GetXGBShortcut(FormatShortcut(k))
		keyInfo := NewKeyCodeInfo(shortcut)
		if keyInfo == nil {
			continue
		}

		if grab {
			if GrabKeyPress(X.RootWin(), shortcut) {
				GrabKeyBinds[keyInfo] = v
			}
		} else {
			UngrabKey(X.RootWin(), shortcut)
			delete(GrabKeyBinds, keyInfo)
		}
	}
}

func GrabKeyPress(wid xproto.Window, shortcut string) bool {
	if len(shortcut) <= 0 {
		fmt.Println("grab key args failed...")
		return false
	}

	mod, keys, err := keybind.ParseString(X, shortcut)
	if err != nil {
		fmt.Printf("grab parse shortcut string failed: %s\n", err)
		return false
	}

	err = keybind.GrabChecked(X, wid, mod, keys[0])
	if err != nil {
		fmt.Printf("Grab '%s' Failed: %s\n", shortcut, err)
		return false
	}

	return true
}

func UngrabKey(wid xproto.Window, shortcut string) bool {
	if len(shortcut) <= 0 {
		return false
	}

	mod, keys, err := keybind.ParseString(X, shortcut)
	if err != nil {
		fmt.Printf("ungrab parse shortcut string failed: %s\n", err)
		return false
	}

	keybind.Ungrab(X, wid, mod, keys[0])

	return true
}

func GetExecAction(k1 *KeyCodeInfo) (bool, string) {
	for k, v := range GrabKeyBinds {
		if k1.State == k.State && k.Detail == k1.Detail {
			return true, v
		}
	}

	return false, ""
}

func ExecCommand(value string) {
	var cmd *exec.Cmd
	vals := strings.Split(value, " ")
	l := len(vals)

	if l > 0 {
		args := []string{}
		for i := 1; i < l; i++ {
			args = append(args, vals[i])
		}
		/*fmt.Println("args: ", args)*/
		cmd = exec.Command(vals[0], args...)
	} else {
		cmd = exec.Command(value)
	}
	_, err := cmd.Output()
	if err != nil {
		fmt.Println("Exec command failed:", err)
	}
}

func ListenKeyPressEvent() {
	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			fmt.Printf("State: %d, Detail: %d\n",
				e.State, e.Detail)
			tmpInfo := NewKeyCodeInfo(
				keybind.LookupString(X, e.State, e.Detail))
			if ok, v := GetExecAction(tmpInfo); ok {
				// 不然按键会阻塞，直到程序推出
				go ExecCommand(v)
			}
		}).Connect(X, X.RootWin())
}
